package com.aleyn.router.inject

import com.aleyn.router.inject.instance.InstanceData
import com.aleyn.router.inject.instance.InstanceFactory
import com.aleyn.router.inject.instance.InstanceRegistry
import com.aleyn.router.inject.instance.Parameters
import com.aleyn.router.inject.instance.mappingKey
import com.aleyn.router.inject.qualifier.Qualifier
import kotlin.reflect.KClass

/**
 * @author: Aleyn
 * @date: 2023/7/27 11:50
 *
 * 依赖注入框架的核心。
 * 这是一个单例对象，作为与注入框架交互的主要入口点。
 */
object Core {

    // 实例注册表，用于存储和管理所有的实例工厂
    val instanceRegistry = InstanceRegistry()

    /**
     * 保存一个实例工厂到注册表。
     *
     * @param instanceFactory 要保存的实例工厂。
     */
    fun saveFactory(instanceFactory: InstanceFactory<*>) {
        val definition = instanceFactory.definition
        val mapping = mappingKey(definition.primaryType, definition.qualifier)

        instanceRegistry.saveMapping(mapping, instanceFactory)
    }

    /**
     * 获取一个类型的实例。
     *
     * @param T 要获取的实例类型。
     * @param qualifier 可选的限定符，用于区分同一类型的不同实例。
     * @param parameters 可选的参数，用于在创建实例时传递。
     * @return 实例。
     */
    inline fun <reified T : Any> get(
        qualifier: Qualifier? = null,
        parameters: Parameters? = null
    ): T {
        return get(T::class, qualifier, parameters)
    }

    /**
     * 获取一个类型的实例。
     *
     * @param T 泛型参数，表示期望返回的实例类型。
     * @param clazz 要获取实例的 KClass。
     * @param qualifier 可选的限定符。
     * @param parameterDef 可选的参数定义。
     * @return 实例。
     */
    fun <T> get(
        clazz: KClass<*>,
        qualifier: Qualifier? = null,
        parameterDef: Parameters? = null
    ): T {
        val instanceContext = InstanceData(parameterDef)
        return resolveValue(qualifier, clazz, instanceContext)
    }

    /**
     * 安全地获取一个类型的实例，如果找不到则返回 null。
     *
     * @param T 要获取的实例类型。
     * @param qualifier 可选的限定符。
     * @param parameters 可选的参数。
     * @return 实例或 null。
     */
    inline fun <reified T : Any> getOrNull(
        qualifier: Qualifier? = null,
        parameters: Parameters? = null
    ): T? {
        return getOrNull(T::class, qualifier, parameters)
    }

    /**
     * 安全地获取一个类型的实例，如果找不到则返回 null。
     *
     * @param T 泛型参数，表示期望返回的实例类型。
     * @param clazz 要获取实例的 KClass。
     * @param qualifier 可选的限定符。
     * @param parameters 可选的参数。
     * @return 实例或 null。
     */
    fun <T> getOrNull(
        clazz: KClass<*>,
        qualifier: Qualifier? = null,
        parameters: Parameters? = null
    ): T? {
        return try {
            get(clazz, qualifier, parameters)
        } catch (e: Exception) {
            null
        }
    }

    /**
     * 获取某个类型的所有已注册实例。
     *
     * @param T 要获取的实例类型。
     * @return 实例列表。
     */
    inline fun <reified T : Any> getAll(): List<T> = getAll(T::class)

    /**
     * 获取某个类型的所有已注册实例。
     *
     * @param T 泛型参数，表示期望返回的实例类型。
     * @param clazz 要获取实例的 KClass。
     * @return 实例列表。
     */
    fun <T> getAll(clazz: KClass<*>): List<T> {
        return instanceRegistry.getAll(clazz)
    }


    /**
     * 关闭并释放所有资源。
     */
    fun close() {
        instanceRegistry.close()
    }

    /**
     * 创建所有被标记为“急切”的单例实例。
     * 通常在应用启动时调用。
     */
    fun createEagerInstances() {
        instanceRegistry.createAllEagerInstances()
    }

    /**
     * 解析并返回一个实例。
     * 这是实际解析依赖关系的内部函数。
     *
     * @param qualifier 限定符。
     * @param clazz 实例的 KClass。
     * @param instanceContext 实例上下文，包含创建参数。
     * @return 解析出的实例。
     * @throws error 如果找不到对应的实例。
     */
    private fun <T> resolveValue(
        qualifier: Qualifier?,
        clazz: KClass<*>,
        instanceContext: InstanceData,
    ): T = instanceRegistry.resolveInstance(qualifier, clazz, instanceContext)
        ?: error("${clazz.qualifiedName} not found ")

}